/* ----------------------------------------------------------------------
 *	Shadow Quest
 *	Copyright (C) 2009 Prageeth Silva <prageeth@thenewcoders.com>
 *
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *  ----------------------------------------------------------------------
 */
package panel;

import map.World;

import org.newdawn.slick.Color;
import org.newdawn.slick.Graphics;
import org.newdawn.slick.Input;
import org.newdawn.slick.SlickException;


import sq.FontLoader;
import sq.RPG;
import sq.game.Quest;
import units.Unit;

public class Minimap {

    private static final double MINIMAP_TRANSITION_RATE = 0.4;
    private static final int MINIMAP_WIDTH = 150;
    private static final int MINIMAP_HEIGHT = 150;
    private static final int MINIMAP_BORDER = 5;
    private static final int MINIMAP_X_MAX = 0;
    private static final int MINIMAP_Y = RPG.getScreenHeight() - MINIMAP_HEIGHT - 2 * MINIMAP_BORDER;
    private static int MINIMAP_X = MINIMAP_X_MAX - MINIMAP_WIDTH - 2 * MINIMAP_BORDER;
    private Color minimap[][];							// the minimap
    private boolean minimapTransition, minimapStatus;	// the minimap transition, the status of the minimap visibility
    private World world;

    public Minimap(World world)
            throws SlickException {

        this.minimap = new Color[MINIMAP_WIDTH + 1][MINIMAP_HEIGHT + 1];
        this.setShown(false);
        this.setWorld(world);

    }

    /** Loads the world minimap.
     * @param world The world of which the minimap should be drawn.
     */
    public void update(Input input, int delta) {

        boolean minimap_key = input.isKeyPressed(Input.KEY_TAB);

        if (minimap_key || !this.isTransitionDone()) {
            this.setTransitionDone(false);
            if (!this.isShown()) {
                this.show(delta);
            } else {
                this.hide(delta);
            }
        }

        // update the minimap only of needed.
        if (this.isShown() || !this.isTransitionDone()) {
            this.update();
        }

    }

    /** Loads the world minimap.
     * @param world The world of which the minimap should be drawn.
     */
    private void update() {

        int tileWidth = this.getWorld().getMap().getTileWidth();
        int tileHeight = this.getWorld().getMap().getTileHeight();
        double scaleX = (double) MINIMAP_WIDTH / this.getWorld().getWidthInTiles();
        double scaleY = (double) MINIMAP_HEIGHT / this.getWorld().getHeightInTiles();

        // load the map
        for (int x = 0; x < MINIMAP_WIDTH; x++) {
            for (int y = 0; y < MINIMAP_HEIGHT; y++) {
                int ix = (int) Math.floor(x / scaleX), iy = (int) Math.floor(y / scaleY);
                minimap[x][y] = this.getWorld().getTileColors()[ix][iy];
            }
        }

        // set the monsters
        for (Unit u : this.getWorld().getAllOtherUnits()) {
            if (u.isAlive()) {

                int ix = (int) Math.floor(u.getX() / tileWidth * scaleX), iy = (int) Math.floor(u.getY() / tileHeight * scaleY);

                Color c = FontLoader.getMonesterBgColor();
                if (this.getWorld().getQuest().getCurrentPlayer().isAlly(u)) {
                    c = FontLoader.getMinimapAllyColor();
                } else if (Unit.isVillager(u)) {
                    c = FontLoader.getMinimapVillagerColor();
                }

                minimap[ix][iy] = c;
                minimap[ix + 1][iy] = c;
                minimap[ix][iy + 1] = c;
                minimap[ix + 1][iy + 1] = c;

            }
        }

        // set the player
        int ix = (int) Math.floor(this.getWorld().getPlayer().getX() / tileWidth * scaleX), iy = (int) Math.floor(this.getWorld().getPlayer().getY() / tileHeight * scaleY);
        minimap[ix][iy] = FontLoader.getMinimapPlayerColor();
        minimap[ix + 1][iy] = FontLoader.getMinimapPlayerColor();
        minimap[ix][iy + 1] = FontLoader.getMinimapPlayerColor();
        minimap[ix + 1][iy + 1] = FontLoader.getMinimapPlayerColor();

    }

    /** Renders the player's status panel.
     * @param g The current Slick graphics context.
     */
    public void render(Graphics g) {

        if (this.isShown() || !this.isTransitionDone()) {

            int m_y = MINIMAP_Y - Panel.getPanelHeight() + Panel.getPanelGap(), x0 = MINIMAP_X + MINIMAP_BORDER, y0 = m_y + MINIMAP_BORDER;
            g.setColor(FontLoader.getDialogueBgColor());
            g.fillRect(MINIMAP_X, m_y, MINIMAP_WIDTH + 2 * MINIMAP_BORDER, MINIMAP_HEIGHT + 2 * MINIMAP_BORDER);
            g.setColor(Color.black);
            g.fillRect(x0, y0, MINIMAP_WIDTH, MINIMAP_HEIGHT);
            for (int x = 0; x < MINIMAP_WIDTH; x++) {
                for (int y = 0; y < MINIMAP_HEIGHT; y++) {
                    g.setColor(minimap[x][y]);
                    g.fillRect(x0 + x, y0 + y, 1, 1);
                }
            }

        }

    }

    /** Win the game, and change the state of the whole game to WON.
     * @param delta Time passed since last frame (milliseconds).
     */
    protected void show() {
        this.setTransitionDone(false);
    }

    /** Win the game, and change the state of the whole game to WON.
     * @param delta Time passed since last frame (milliseconds).
     */
    private void show(int delta) {
        if (!this.isTransitionDone()) {
            MINIMAP_X += Math.floor(MINIMAP_TRANSITION_RATE * delta);
            if (MINIMAP_X >= MINIMAP_X_MAX) {
                MINIMAP_X = MINIMAP_X_MAX;
                this.setShown(true);
                this.setTransitionDone(true);
            }
        }
    }

    /** Win the game, and change the state of the whole game to WON.
     * @param delta Time passed since last frame (milliseconds).
     */
    protected void hide() {
        this.setTransitionDone(false);
    }

    /** Win the game, and change the state of the whole game to WON.
     * @param delta Time passed since last frame (milliseconds).
     */
    private void hide(int delta) {
        if (!this.isTransitionDone()) {
            MINIMAP_X -= Math.floor(MINIMAP_TRANSITION_RATE * delta);
            int max = MINIMAP_X_MAX - MINIMAP_WIDTH - (2 * MINIMAP_BORDER);
            if (MINIMAP_X <= max) {
                MINIMAP_X = max;
                this.setShown(false);
                this.setTransitionDone(true);
            }
        }
    }

    /** Get the minimap's status.
     * @return panelStatus The panel's status.
     */
    protected boolean isShown() {
        return this.minimapStatus;
    }

    /** Set the minimap's status.
     * @param status The minimap's status.
     */
    private void setShown(boolean status) {
        this.minimapStatus = status;
    }

    /** Get the minimap's transition status.
     * @return inventory.
     */
    protected boolean isTransitionDone() {
        return this.minimapTransition;
    }

    /** Set the minimap's transition status.
     * @param minimapTransition The transition status.
     */
    private void setTransitionDone(boolean minimapTransition) {
        this.minimapTransition = minimapTransition;
    }

    public World getWorld() {
        return this.world;
    }

    public void setWorld(World world) {
        this.world = world;
    }
}
